////////////////////////////////////////
//	File Header
//	Author: Stephen Ringer | stephen.ringer@gmail.com
//	File: SAGADI.h
//
////////////////////////////////////////
#pragma once
////////////////////////////////////////
//	File Includes
#include <windows.h>
#include "../SAGAInput/SAGAInputDevice.h"
#include "../SAGAD3D/SAGA.h"
#include <dinput.h>
//
////////////////////////////////////////

////////////////////////////////////////
//	Macros
#define DIRECTINPUT_VERSION 0x0800
//
////////////////////////////////////////

////////////////////////////////////////
//	Helper Functions
BOOL WINAPI DllEntryPoint( HINSTANCE hDll, DWORD     fdwReason, LPVOID    lpvRserved );
//
////////////////////////////////////////

////////////////////////////////////////
//	Forward Declarations
class SAGAKeyboard;
class SAGAMouse;
class SAGAJoystick;
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGADI
//	Purpose:
//		Class definition for a Direct3D render device, implementing the
//		interface SAGARenderDevice
class SAGADI : public SAGAInputDevice 
{
public:
	SAGADI(HINSTANCE hDLL);
	~SAGADI();

	// initialize the engine stuff
	HRESULT Init(HWND, const RECT*, bool);

	// Interface functions
	void    Release();
	bool    IsRunning() { return m_bRunning; }
	bool    HasJoystick(char *pJoyName);
	HRESULT Update();

	// query input data and states
	HRESULT GetPosition(SAGAINPUTDEV idType, POINT *pPt);
	HRESULT GetJoyDeflection(float*, float*);
	POINT   GetMouseDelta();
	bool    IsPressed(SAGAINPUTDEV idType, UINT nBtn);
	bool    IsReleased(SAGAINPUTDEV idType, UINT nBtn);
  

private:
	LPDIRECTINPUT8  m_pDI; 
	SAGAKeyboard    *m_pKB;
	SAGAMouse       *m_pMouse;
	SAGAJoystick    *m_pJoy;

	// write to log file
	void Log(char *, ...);
}; 
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGADIDevice
//	Purpose:
//		Joystick / Gamepad Device
class SAGADIDevice 
{
public:
	SAGADIDevice() { /*nothing*/; }
	virtual ~SAGADIDevice() { /*nothing*/; }

	// base class methods
	virtual void    Create(LPDIRECTINPUT8, HWND, FILE*);
	virtual void    Release();
	virtual HRESULT CrankUp(REFGUID rguid, LPCDIDATAFORMAT lpdf);

	// Accessor-Methods
	virtual void    GetPosition(POINT *pPoint)
	 { (*pPoint).x = m_lX; (*pPoint).y = m_lY; }

	// virtual methods for heirs
	virtual HRESULT Init()=0;
	virtual HRESULT Update()=0;

protected:
	virtual HRESULT GetData(SAGAINPUTDEV Type, void *pData, DWORD *dwNum);

	LPDIRECTINPUTDEVICE8  m_pDevice;
	LPDIRECTINPUT8        m_pDI;
	HWND                  m_hWnd;
	long                  m_lX;
	long                  m_lY;
	FILE                 *m_pLog;
	void Log(char *, ...);
}; 
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGAKeyboard
//	Purpose:
//		Keyboard Device
class SAGAKeyboard : public SAGADIDevice 
{
public:
	SAGAKeyboard(LPDIRECTINPUT8, HWND, FILE*);
	virtual ~SAGAKeyboard(void);

	HRESULT Init();
	HRESULT Update();

	bool    IsPressed(UINT nID);
	bool    IsReleased(UINT nID);

private:
	char  m_Keys[256];
	char  m_KeysOld[256];
}; 
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGAMouse
//	Purpose:
//		Mouse Device
class SAGAMouse : public SAGADIDevice 
{
public:
	SAGAMouse(LPDIRECTINPUT8, HWND, FILE*);
	virtual ~SAGAMouse();

	HRESULT Init();
	HRESULT Update();

	void  SetCage(RECT rcCage) { m_rcCage = rcCage; }
	POINT GetMouseDelta() { return m_Delta; }

	bool IsPressed(UINT nBtn) 
	 { if (nBtn<3) return m_bPressed[nBtn]; return false; }
	bool IsReleased(UINT nBtn)
	 { if (nBtn<3) return m_bReleased[nBtn]; return false; }

private:
	HANDLE     m_hEvent;
	RECT       m_rcCage;
	bool       m_bPressed[3];
	bool       m_bReleased[3];
	POINT      m_Delta;
}; 
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGAJoystick
//	Purpose:
//		Joystick / Gamepad Device
class SAGAJoystick : public SAGADIDevice 
{
public:
	SAGAJoystick(LPDIRECTINPUT8, HWND, FILE*);
	virtual ~SAGAJoystick(void);

	HRESULT Init(void);
	HRESULT Update(void);

	bool JoystickFound(void) { return m_bJoyFound; }
	BOOL EnumJoyCallback(const DIDEVICEINSTANCE *pInst);

	void GetName(char *pJoyName) 
	 { memcpy(pJoyName, m_Name, sizeof(char)*256); }

	bool IsPressed(UINT nBtn) 
	 { if (nBtn<m_dwNumBtns) return m_bPressed[nBtn]; return false; }

	bool IsReleased(UINT nBtn) 
	 { if (nBtn<m_dwNumBtns) return m_bReleased[nBtn]; return false; }

	HRESULT GetJoyDeflection(float *pfX, float *pfY);

private:
	GUID       m_guid;
	char       m_Name[256];
	bool       m_bJoyFound;
	bool       m_bPressed[12];
	bool       m_bReleased[12];
	DWORD      m_dwNumBtns;
}; 
//
////////////////////////////////////////